﻿#region GNU GPL Version 3 License

/// Copyright 2013 Shailesh Lolam
/// 
/// This file DeploymentService.cs is part of AzEzAuto.
/// 
/// AzEzAuto is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
/// 
/// AzEzAuto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
/// 
/// You should have received a copy of the GNU General Public License along with AzEzAuto. If not, see http://www.gnu.org/licenses/.
/// 
/// History:
/// ______________________________________________________________
/// Created         04-2013             Shailesh Lolam

#endregion
      
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XecMe.Core.Tasks;
using Microsoft.WindowsAzure.Storage;
using System.Configuration;
using Microsoft.WindowsAzure.Storage.Queue;
using AzEzAuto.Management;
using AzEzAuto.Entities.Requests;
using AzEzAuto.Entities.Hosted;

namespace AzEzAuto.Orchestrate.Tasks
{
    public class DeploymentService : BaseTask
    {
        protected override ExecutionState Process(Request req)
        {
            ///If there is no Deployment part in the request, just move it to next guy in the pipeline
            if (req.Deployment == null)
            {
                WriteToOutputQueue(req);
                return ExecutionState.Executed;
            }

            switch (req.Deployment.Operation)
            {
                case DeploymentBase.OperationType.Deploy:
                    {
                        AzEzAuto.Entities.Requests.Deployment d = (Entities.Requests.Deployment)req.Deployment;
                        CreateDeployment r = new CreateDeployment()
                        {
                            Configuration = this.LoadConfigFromUrl(d.Configuration),
                            Label = d.Label,
                            Name = d.Name,
                            PackageUrl = string.Concat(d.PackageUrl, "&", this.GetSharedAccessSignature(req.SubscriptionId)),
                            StartDeployment = d.StartDeployment,
                            TreatWarningsAsError = d.TreatWarningsAsError
                        };
                        CopyProperties(d.Properties, r.ExtendedProperties);
                        if (d.ExtensionConfiguration != null)
                        {
                            CopyExtensionConfiguration(d.ExtensionConfiguration, r.ExtensionConfiguration);
                        }
                        req.CurrentRequestId = _api.Cloud.CreateDeployment(req.SubscriptionId, r, d.ServiceName, d.DeploymentSlot);
                    }
                    break;
                case DeploymentBase.OperationType.Upgrade:
                    {
                        AzEzAuto.Entities.Requests.Upgrade u = (AzEzAuto.Entities.Requests.Upgrade)req.Deployment;
                        UpgradeDeployment r = new UpgradeDeployment()
                        {
                            Configuration = this.LoadConfigFromUrl(u.Configuration),
                            Force = u.Force,
                            Label = u.Label,
                            Mode = u.Mode,
                            PackageUrl = string.Concat(u.PackageUrl, "&", this.GetSharedAccessSignature(req.SubscriptionId)),
                            RoleToUpgrade = u.RoleToUpgrade
                        };
                        CopyProperties(u.Properties, r.ExtendedProperties);
                        if (string.IsNullOrEmpty(u.DeploymentName))
                            req.CurrentRequestId = _api.Cloud.UpgradeDeployment(req.SubscriptionId, r, u.ServiceName, u.DeploymentSlot);
                        else
                            req.CurrentRequestId = _api.Cloud.UpgradeDeployment(req.SubscriptionId, r, u.ServiceName, u.DeploymentName);
                    }
                    break;
                case DeploymentBase.OperationType.Swap:
                    {
                        AzEzAuto.Entities.Requests.Swap s = (AzEzAuto.Entities.Requests.Swap)req.Deployment;
                        AzEzAuto.Entities.Hosted.Swap r = new Entities.Hosted.Swap()
                        {
                            Production = s.Production,
                            SourceDeployment = s.SourceDeployment
                        };
                        req.CurrentRequestId = _api.Cloud.SwapDeployment(req.SubscriptionId, r, s.ServiceName);
                    }
                    break;
                case DeploymentBase.OperationType.Change:
                    {
                        ChangeConfig c = (ChangeConfig)req.Deployment;
                        ChangeConfiguration r = new ChangeConfiguration()
                        {
                            Configuration = this.LoadConfigFromUrl(c.Configuration),
                            Mode = c.Mode,
                            TreatWarningsAsError = c.TreatWarningsAsError
                        };
                        CopyProperties(c.Properties, r.ExtendedProperties);
                        if (string.IsNullOrEmpty(c.DeploymentName))
                            req.CurrentRequestId = _api.Cloud.ChangeDeploymentConfig(req.SubscriptionId, r, c.ServiceName, c.DeploymentSlot);
                        else
                            req.CurrentRequestId = _api.Cloud.ChangeDeploymentConfig(req.SubscriptionId, r, c.ServiceName, c.DeploymentName);
                    }
                    break;
                case DeploymentBase.OperationType.UpdateStatus:
                    {
                        AzEzAuto.Entities.Requests.UpdateDeploymentStatus uds = (AzEzAuto.Entities.Requests.UpdateDeploymentStatus)req.Deployment;
                        AzEzAuto.Entities.Hosted.UpdateDeploymentStatus r = new Entities.Hosted.UpdateDeploymentStatus()
                        {
                            Status = uds.Status
                        };

                        if (string.IsNullOrEmpty(uds.DeploymentName))
                            req.CurrentRequestId = _api.Cloud.UpdateDeploymentStatus(req.SubscriptionId, r, uds.ServiceName, uds.DeploymentSlot);
                        else
                            req.CurrentRequestId = _api.Cloud.UpdateDeploymentStatus(req.SubscriptionId, r, uds.ServiceName, uds.DeploymentName);
                    }
                    break;
                case DeploymentBase.OperationType.Delete:
                    {
                        DeleteDeployment dd = (DeleteDeployment)req.Deployment;
                        if (string.IsNullOrEmpty(dd.DeploymentName))
                            req.CurrentRequestId = _api.Cloud.DeleteDeployment(req.SubscriptionId, dd.ServiceName, dd.DeploymentSlot);
                        else
                            req.CurrentRequestId = _api.Cloud.DeleteDeployment(req.SubscriptionId, dd.ServiceName, dd.DeploymentName);
                    }
                    break;
                default:
                    throw new InvalidOperationException(string.Format("Unknown operation {0} for the Deployment Service for subscription {1}", req.Deployment.Operation, req.SubscriptionId));
            }

            return ExecutionState.Executed;
        }

        private void CopyExtension(List<AzEzAuto.Entities.Requests.Extension> src, List<AzEzAuto.Entities.Hosted.Extension> dest)
        {
            for (int i = 0; i < src.Count; i++)
            {
                AzEzAuto.Entities.Requests.Extension extn = src[i];
                dest.Add(new Entities.Hosted.Extension() { Id = extn.Id });
            }
        }

        private void CopyExtensionConfiguration(AzEzAuto.Entities.Requests.ExtensionConfiguration src, AzEzAuto.Entities.Hosted.ExtensionConfiguration dest)
        {
            CopyExtension(src.AllRoles, dest.AllRoles);
            for (int i = 0; i < src.NamedRoles.Count; i++)
            {
                AzEzAuto.Entities.Requests.ExtRole srcRole = src.NamedRoles[i];
                AzEzAuto.Entities.Hosted.ExtRole destRole = new Entities.Hosted.ExtRole() { RoleName = srcRole.RoleName };
                dest.NamedRoles.Add(destRole);
                CopyExtension(srcRole.Extensions, destRole.Extensions);
            }
        }
    }
}
